﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KeshaParser
{
    abstract class GrammarItem
    {
    }

    class NonTerminal : GrammarItem
    {
        public string Id { get; protected set; }

        public NonTerminal(string id)
        {
            Id = id;
        }

        public bool IsEpsilon()
        {
            return Id.CompareTo("<e>") == 0;
        }

        public override string ToString()
        {
            return Id;
        }

        public override bool Equals(object obj)
        {
            NonTerminal other = obj as NonTerminal;
            if (other == null)
            {
                return base.Equals(obj);
            }
            return Id.CompareTo(other.Id) == 0;
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }
    }

    class Derivation : List<GrammarItem>
    {
    }

    class GrammarTable
    {
        private Dictionary<KeyValuePair<NonTerminal, Token>, Derivation> table;

        public GrammarTable()
        {
            table = new Dictionary<KeyValuePair<NonTerminal, Token>, Derivation>();
            LoadFromFile("grammar_table.kesh");
        }

        public Derivation LookUp(NonTerminal nt, Token t)
        {
            KeyValuePair<NonTerminal, Token> pair = new KeyValuePair<NonTerminal, Token>(nt, t);

            if (table.ContainsKey(pair))
            {
                return table[pair];
            }
            
            return null;
        }

        public NonTerminal GetStartSymbol()
        {
            return new NonTerminal("<A>");
        }
        
        private void LoadFromFile(string filePath)
        {
            string[] lines = File.ReadAllLines(filePath);
            foreach (string fileLine in lines)
            {
                string line = fileLine;
                line = line.Replace("\r", "");
                line = line.Replace("\n", "");
                string[] lineItems = line.Split('\t');
                NonTerminal nt = new NonTerminal(lineItems[0]);
                Token t = KeywordTokenCreator.CreateByString(lineItems[1]);
                Derivation d = new Derivation();
                string[] derivationItems = lineItems[2].Split(' ');
                foreach (string derivationItem in derivationItems)
                {
                    if (derivationItem[0] == '<' &&
                        derivationItem[derivationItem.Length - 1] == '>')
                    {
                        d.Add(new NonTerminal(derivationItem));
                    }
                    else
                    {
                        d.Add(KeywordTokenCreator.CreateByString(derivationItem));
                    }
                }

                AddDerivation(nt, t, d);
            }
        }

        private void AddDerivation(NonTerminal nt, Token t, Derivation d)
        {
            KeyValuePair<NonTerminal, Token> pair = new KeyValuePair<NonTerminal, Token>(nt, t);

            if (table.ContainsKey(pair))
            {
                throw new Exception("Your have non-LL(1) parse table.");
            }

            table[pair] = d;
        }
    }
}
